home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
commands
/
ttt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-19
|
6KB
|
281 lines
/* tic tac toe (noughts and crosses) Author: Warren Toomey */
/* Copyright (C) 1988 Warren Toomey.
You may use, copy, modify, or give this away provided you
1. make the source available with every copy.
2. include this notice.
3. don't use this for military purposes.
(but you can take credit for improvements, etc.)
*/
/* Compile with cc -o tic tic.c -lcurses -ltermcap */
#define CURSES
#ifdef CURSES
/* #include <curses.h> Used by the real curses */
#endif
#ifndef CURSES
#define printw printf
#endif
typedef struct {
int value; /* The move returned by the */
int path; /* alphabeta consists of a value */
} MOVE; /* and an actual move (path) */
/* Static evaluator. Returns 100 if we have 3 in a row -100 if they have 3
* in a row
*
* Board is array of 9 ints, where 0=empty square 1=our move 4= their move
*
* and board is indices 0 1 2 3 4 5 6 7 8 */
int stateval(board, whosemove)
int board[];
{
static int row[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, /* Indices of 3in-a-rows */
{0, 3, 6}, {1, 4, 7}, {2, 5, 8},
{0, 4, 8}, {2, 4, 6}};
int temp; /* Temp row results */
int i, j; /* Loop counters */
int side; /* Depth multiplier */
int win, lose;
if (whosemove == 1) {
win = 100;
lose = -100;
side = 1;
} else {
/* Multiply by -1 if */
win = -100;
lose = 100;
side = -1;
} /* not out move */
for (i = 0; i < 8; i++) { /* For every 3-in-a-row */
temp = 0;
for (j = 0; j < 3; j++) /* Add up the board values */
temp += board[row[i][j]];
if (temp == 3) return(win); /* We've got 3 in a row */
if (temp == 12) return (lose); /* They've got 3 in a row */
}
return(0); /* Finally return sum */
}
MOVE alphabeta(board, whosemove, alpha, beta) /* Alphabeta: takes a board, */
int board[]; /* whose move, alpha & beta cutoffs, */
int whosemove; /* and returns a move to make and */
int alpha; /* the value that the move has */
int beta;
{
MOVE result, successor;
int best_score, i, best_path, mademove;
result.value = stateval(board, whosemove); /* Work out the board's */
/* Static value */
if ((result.value == 100) || /* If a win or loss already */
(result.value == -100))
return(result); /* return the result */
best_score = beta; /* Ok, set worst score */
mademove = 0; /* to the beta cutoff */
for (i = 0; i < 9; i++) {
if (board[i] == 0) { /* For all valid moves */
mademove = 1;
board[i] = whosemove; /* make the move on board */
successor = alphabeta(board, 5 - whosemove, -best_score - 1, -alpha - 1);
/* Get value of the move */
board[i] = 0; /* Take move back */
if (-successor.value > best_score) { /* If a better score */
best_score = -successor.value; /* update our score */
best_path = i; /* and move */
if (best_score > alpha)
break; /* If we've beaten alpha */
} /* return immediately */
}
}
if (mademove) {
result.value = best_score; /* Finally return best score */
result.path = best_path;/* and best move */
}
return(result); /* If no move, return static result */
}
draw(board) /* Draw the board */
int board[];
{
int i, j, row;
static char out[] = " X O"; /* Lookup table for character */
row = 6;
#ifdef CURSES
move(row, 0);
#endif
for (j = 0; j < 9; j += 3) {
printw(" %d | %d | %d ", j, j + 1, j + 2);
for (i = 0; i < 3; i++) {
printw("%c ", out[board[j + i]]);
if (i < 2) printw("| ");
}
if (j < 4) {
#ifdef CURSES
move(++row, 0);
#else
printw("\n");
#endif
printw("---+---+--- ---+---+---");
}
#ifdef CURSES
move(++row, 0);
#else
printw("\n");
#endif
}
#ifdef CURSES
refresh();
#else
printw("\n");
#endif
}
getmove(board) /* Get a player's move */
int board[];
{
int Move;
do {
do {
#ifdef CURSES
move(9, 40);
printw("Your move: "); /* Prompt for move */
refresh();
#else
printw("Your move: "); /* Prompt for move */
#endif
}
while (scanf("%d", &Move) != 1); /* Input the move */
}
while (board[Move]);
board[Move] = 4; /* If legal, add to board */
draw(board); /* Draw the board */
}
int endofgame(board) /* Determine end of the game */
int board[];
{
int eval;
int count;
eval = stateval(board, 1);
#ifdef CURSES
move(20, 25);
#endif
if (eval == 100) {
printw("I have beaten you.\n");
return(1);
}
if (eval == -100) {
printw("Bus error (core dumped)\n");
return(1);
}
count = 0;
for (eval = 0; eval < 9; eval++)
if (board[eval] != 0) count++;
if (count == 9) {
printw("A draw!\n");
return(1);
}
#ifdef CURSES
refresh();
#endif
return(0);
}
int randommove()
{ /* Make an initial random move */
long time(); /* based on current time */
int i;
i = abs((int) time((long *) 0));
return(i % 9);
}
main()
{ /* The actual game */
int i, board[9];
char ch;
MOVE ourmove;
for (i = 0; i < 9; i++) board[i] = 0; /* Initialise the board */
#ifdef CURSES
initscr();
clear();
refresh();
#endif
printw(" TIC TAC TOE \n\n");
printw(" Your moves are 'O'\n");
printw(" My moves are 'X'\n\n");
#ifdef CURSES
move(5, 0);
printw("Do you wish to move first: ");
refresh();
while (scanf("%c", &ch) != 1);
move(5, 0);
printw(" ......."); /* Kludge to get rid */
refresh();
move(5, 0);
printw(" "); /* of input letter */
refresh();
#else
do
printw("Do you wish to move first: ");
while (scanf("%c", &ch) != 1);
#endif
if ((ch != 'y') && (ch != 'Y')) {
i = randommove(); /* If we move first */
board[i] = 1; /* make it random */
#ifdef CURSES
move(7, 42);
printw("My move: %d\n", i);
refresh();
#else
printw("My move: %d\n", i);
#endif
}
draw(board);
getmove(board);
while (1) {
ourmove = alphabeta(board, 1, 99, -99); /* Get a move for us;
* return wins */
/* Immediately & ignore losses */
board[ourmove.path] = 1;/* and make it */
#ifdef CURSES
move(7, 42);
printw("My move: %d\n", ourmove.path);
refresh();
#else
printw("My move: %d\n", ourmove.path);
#endif
draw(board);
if (endofgame(board)) break; /* If end of game, exit */
getmove(board); /* Get opponent's move */
if (endofgame(board)) break; /* If end of game, exit */
}
#ifdef CURSES
endwin();
#endif
}